package com.nervenets.shopping.scheduler;

import com.nervenets.general.aspect.RedisLocker;
import com.nervenets.general.utils.JodaUtils;
import com.nervenets.shopping.enumeration.OrderStatus;
import com.nervenets.shopping.hibernate.domain.common.GlobalRuleSetting;
import com.nervenets.shopping.hibernate.domain.data.DataOfDayState;
import com.nervenets.shopping.hibernate.domain.order.GroupBuyOrderUser;
import com.nervenets.shopping.service.*;
import lombok.extern.slf4j.Slf4j;
import org.springframework.scheduling.annotation.EnableScheduling;
import org.springframework.scheduling.annotation.Scheduled;
import org.springframework.stereotype.Component;

import javax.annotation.Resource;
import java.util.List;

@Slf4j
@Component
@EnableScheduling
public class Task {
    @Resource
    private GlobalRuleService globalRuleService;
    @Resource
    private DataOfUserService dataOfUserService;
    @Resource
    private DataOfDayStateService dataOfDayStateService;
    @Resource
    private DataOfWeekService dataOfWeekService;
    @Resource
    private GroupBuyOrderService groupBuyOrderService;
    @Resource
    private GroupBuyOrderUserService groupBuyOrderUserService;
    @Resource
    private BonusSharingService bonusSharingService;
    @Resource
    private UserService userService;

    /**
     * 每8秒钟执行
     */
    @Scheduled(cron = "*/8 * * * * *")
    @RedisLocker(lockKey = "SchedulerTask.every8SecondsExecute", holdTime = 8)
    public void every18MinutesExecute() {
        final long start = JodaUtils.getTimestamp();
        System.out.print("SchedulerTask every8SecondsExecute start " + JodaUtils.parseDate(start));

        GlobalRuleSetting setting = globalRuleService.getGlobalRule().getSetting();

        groupBuyOrderUserService.findAll((predicates, root, query, builder) -> {
            predicates.add(builder.equal(root.get("status"), OrderStatus.init));
            predicates.add(builder.lessThan(root.get("createTime"), JodaUtils.getTimestamp() - setting.getOrderAutoCancelMinutes() * 60000L));
        }).forEach(groupBuyOrderUser -> {
            groupBuyOrderUser.setStatus(OrderStatus.cancel);
            groupBuyOrderUserService.save(groupBuyOrderUser);
        });

        groupBuyOrderUserService.findAll((predicates, root, query, builder) -> {
            predicates.add(builder.equal(root.get("status"), OrderStatus.shipped));
            predicates.add(builder.lessThan(root.get("expressTime"), JodaUtils.getTimestamp() - setting.getOrderAutoFinishMinutes() * 60000L));
        }).forEach(groupBuyOrderUser -> {
            groupBuyOrderUser.setStatus(OrderStatus.finish);
            groupBuyOrderUserService.save(groupBuyOrderUser);
        });

        bonusSharingService.handleTop1Unfinished();

        System.out.println(", execute finished, token " + (JodaUtils.getTimestamp() - start) + "ms");
    }

    /**
     * 每3分钟执行检查挑战是否完成
     */
    @Scheduled(cron = "30 */1 * * * *")
    @RedisLocker(lockKey = "SchedulerTask.every3MinutesExecute", holdTime = 10)
    public void every4SecondsExecute() {
        final long start = JodaUtils.getTimestamp();
        System.out.print("SchedulerTask every3MinutesExecute start " + JodaUtils.parseDate(start));

        List<GroupBuyOrderUser> orders = groupBuyOrderUserService.findTopUngroupedOrder(JodaUtils.getTimestamp() - 5 * 60 * 1000);
        for (GroupBuyOrderUser order : orders) {
            groupBuyOrderService.join(order);
        }

        System.out.println(", execute finished, token " + (JodaUtils.getTimestamp() - start) + "ms");
    }


    /**
     * 每小时执行
     */
    @Scheduled(cron = "30 0 * * * *")
    @RedisLocker(lockKey = "SchedulerTask.everyHourExecute", holdTime = 3000)
    public void everyHourExecute() {
        System.out.println("SchedulerTask.everyHourExecute execute...");
        long startOfLastHour = JodaUtils.getStartOfLastHour();

    }

    /**
     * 每天执行
     */
    @RedisLocker(lockKey = "SchedulerTask.everyDayExecute", holdTime = 7200)
    @Scheduled(cron = "0 0 1 ? * *")
    public void everyDayExecute() {
        System.out.println("SchedulerTask.everyDayExecute execute...");
        final long startOfYesterday = JodaUtils.getStartOfYesterday();
        final long endOfYesterday = JodaUtils.getEndOfYesterday();

        //生成明天的基础统计数据
        final long tomorrow = JodaUtils.getEndOfToday() + 1;
        dataOfUserService.checkAndGenerateData(tomorrow);
        dataOfDayStateService.save(DataOfDayState.builder()
                .createTime(startOfYesterday)
                .groupSuccessCount(groupBuyOrderService.count((predicates, root, query, builder) -> predicates.add(builder.between(root.get("successTime"), startOfYesterday, endOfYesterday))))
                .groupUserCount(userService.count((predicates, root, query, builder) -> predicates.add(builder.between(root.get("createTime"), startOfYesterday, endOfYesterday))))
                .sumOfContribution(groupBuyOrderService.sumOfContribution(startOfYesterday, endOfYesterday))
                .sumOfBonus(groupBuyOrderService.sumOfBonus(startOfYesterday, endOfYesterday))
                .sumOfReward(groupBuyOrderUserService.sumOfReward(startOfYesterday, endOfYesterday))
                .sumOfOrderMoney(groupBuyOrderUserService.sumOfOrderMoney(startOfYesterday, endOfYesterday))
                .sumOfRefundMoney(groupBuyOrderUserService.sumOfRefundMoney(startOfYesterday, endOfYesterday))
                .build());
    }

    /**
     * 每周执行
     */
    @RedisLocker(lockKey = "SchedulerTask.everyWeekExecute", holdTime = 7200)
    @Scheduled(cron = "0 0 1 ? * MON")
    public void everyWeekExecute() {
        System.out.println("SchedulerTask.everyWeekExecute execute...");

        dataOfWeekService.checkAndGenerateData(JodaUtils.getStartOfThisWeek());
    }


    /**
     * 每月执行一次
     */
    @RedisLocker(lockKey = "SchedulerTask.everyMonthExecute", holdTime = 7200)
    @Scheduled(cron = "0 0 1 1 * *")
    public void everyMonthExecute() {
        System.out.println("SchedulerTask.everyMonthExecute execute...");

    }

}
